﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Net;
using System.Web;
using System.Windows.Forms;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using Wagner.Utilities;

namespace Wagner.SharePoint.Utilities
{
	internal class FeatCheck : OperationBase
	{
		internal FeatCheck()
		{}

		internal override void Run()
		{
			string url = ValidateParameter("url", true, null);

			RunNow(url);
		}

		#region Properties
		private string _FeatureType;
		private string FeatureType
		{
			get
			{
				return (_FeatureType == null)
					? _FeatureType = ValidateParameter("featureType", false, "All")
					: _FeatureType;
			}
		}

		private string _Scope;
		private string Scope
		{
			get
			{
				return (_Scope == null)
					? _Scope = ValidateParameter("Scope", false, "Web")
					: _Scope;
			}
		}

		private bool Orphans
		{
			get
			{
				return ValidateParameterAsBool("Orphans", false, false);
			}
		}

		private bool AllSites
		{
			get
			{
				return ValidateParameterAsBool("AllSites", false, false);
			}
		}

		private bool AllWebs
		{
			get
			{
				return ValidateParameterAsBool("AllWebs", false, false);
			}
		}
		#endregion 

		private void RunNow(string url)
		{
			using (SPSite site = new SPSite(url))
			{
				Console.WriteLine("Feature Check:");
				Console.WriteLine("  Url:     " + url);
				Console.WriteLine("  Scope:   " + Scope);
				Console.WriteLine("  Type:    " + FeatureType);
				Console.WriteLine("  AllSites:" + AllSites);
				Console.WriteLine("  AllWebs: " + AllWebs);
				Console.WriteLine();

				if (!url.ToLower().Contains(site.Url.ToLower()))
				{
					throw new Exception("Invalid URL specified. http://localhost is not supported with the FeatCheck operation.)");
				}

				if (Scope.Equals("WebApp", StringComparison.InvariantCultureIgnoreCase))
				{
					ProcessWebApp(site.WebApplication);
				}

				if (Scope.Equals("Site", StringComparison.InvariantCultureIgnoreCase))
				{
					ProcessSite(site);
				}

				if (Scope.Equals("Web", StringComparison.InvariantCultureIgnoreCase))
				{
					string webUrl = url.Replace(site.Url, "");
					using (SPWeb web = site.OpenWeb(webUrl))
					{
						CheckFeaturesWeb(web);
					}
				}

				Console.WriteLine();
				Console.WriteLine("Feature Check complete.");
			}
		}

		internal void ProcessWebApp(SPWebApplication webApp)
		{
			CheckFeaturesWebApp(webApp);

			if (AllSites)
			{
				foreach (SPSite site in webApp.Sites)
				{
					try
					{
						ProcessSite(site);
					}
					finally
					{
						site.Dispose();
					}
				}
			}
		}

		internal void ProcessSite(SPSite site)
		{
			CheckFeaturesSite(site);

			if (AllWebs)
			{
				// Process all webs in this site collection.
				foreach (SPWeb web in site.AllWebs)
				{
					try
					{
						// Check features for each web site.
						CheckFeaturesWeb(web);
					}
					finally
					{
						web.Dispose();
					}
				}
			}
			else
			{
				// Process only the root web site.
				using (SPWeb web = site.RootWeb)
				{
					CheckFeaturesWeb(web);
				}
			}
		}

		internal void CheckFeaturesWebApp(SPWebApplication webApp)
		{
			if (FeatureType.Equals("WebApp", StringComparison.InvariantCultureIgnoreCase)
				|| FeatureType.Equals("All", StringComparison.InvariantCultureIgnoreCase))
			{
				Console.WriteLine();
				Console.WriteLine("---------------");
				Console.WriteLine("Web Application: " + Helper.GetWebAppUrl(webApp));
				Console.WriteLine("---------------");
				CheckFeatures(webApp.Features);
			}
		}

		internal void CheckFeaturesSite(SPSite site)
		{
			if (FeatureType.Equals("Site", StringComparison.InvariantCultureIgnoreCase)
				|| FeatureType.Equals("All", StringComparison.InvariantCultureIgnoreCase))
			{
				Console.WriteLine();
				Console.WriteLine("---------------");
				Console.WriteLine("Site Collection: " + site.Url);
				Console.WriteLine("---------------");
				CheckFeatures(site.Features);
			}
		}

		internal void CheckFeaturesWeb(SPWeb web)
		{
			if (FeatureType.Equals("Web", StringComparison.InvariantCultureIgnoreCase)
				|| FeatureType.Equals("All", StringComparison.InvariantCultureIgnoreCase))
			{
				Console.WriteLine();
				Console.WriteLine("--------");
				Console.WriteLine("Web Site: " + web.Url);
				Console.WriteLine("--------");
				CheckFeatures(web.Features);
			}
		}

		internal void CheckFeatures(SPFeatureCollection features)
		{
			foreach (SPFeature feature in features)
			{
				try
				{
					string displayName = feature.Definition.DisplayName;
					string title = feature.Definition.GetTitle(System.Globalization.CultureInfo.CurrentCulture);
					string id = feature.DefinitionId.ToString();
					string hidden = feature.Definition.Hidden ? " (Hidden)" : "";
					if (!Orphans)
					{
						Console.WriteLine(string.Format("{0}{1}", title, hidden));
						Console.WriteLine(string.Format("    Name: {0}", displayName));
						Console.WriteLine(string.Format("    ID: {0}", id));
					}
				}
				catch(Exception ex)
				{
					string id = feature.DefinitionId.ToString();
					Console.WriteLine();
					Console.WriteLine("WARNING: FEATURE DEFINITION NOT FOUND");
					Console.WriteLine(string.Format("    ID: {0}", id));
				}
			}
		}

		internal override string HelpSummary
		{
			get
			{
				return @"
-o FeatCheck
     Check for any orphaned features. (Features that are enabled but no longer
     installed on the server/farm.";
			}
		}

		internal override string HelpDetail
		{
			get
			{
				return HelpSummary + @"
Usage: FIX
  SPDev.exe -o FeatCheck -url <url> [-scope webapp | site | web] -allsites -allwebs
  
    Parameters:  
     -url <url>
       Specifies the url of the web application, site collection, or web site
       defined by the scope parameter.

     [-scope webapp | site | web]
       Defines the scope of the features to check. Default is 'web'. 

     [-featuretype webapp | site | web | all]
       Filters the output to only include the feature type specified. Default
       is 'all'. A value of 'site' will only process site collection features.
       This will exclude all web site features.

     [-allsites]
       Process all sites within the scope of the url. Valid only with a
       scope of 'webapp'.

     [-allwebs]
       Processes all sub web sites within the scope of the url. Valid only with
       a scope of 'webapp' or 'site'.
       
Examples:
  SPDev.exe -o FeatCheck -url http://YourUrl 

 This will only process the web (SPWeb) features having the url specified.
  SPDev.exe -o FeatCheck -url http://YourUrl -scope web

 This will process all the web application features, all site collections, and
 and all web site features.
  SPDev.exe -o FeatCheck -url http://YourUrl -scope webapp -allsites -allwebs

 This will process the site collection features and only the root web site
 features.
  SPDev.exe -o FeatCheck -url http://YourUrl/sites/SiteX -scope site

 This will process the site collection features and the all the web sites.
  SPDev.exe -o FeatCheck -url http://YourUrl/sites/SiteX -scope site -allwebs

 This will process the web sites in the site collection because only 'web' 
 level features will be processed.
  SPDev.exe -o FeatCheck -url http://YourUrl/sites/SiteX -scope site -allwebs -featuretype web
";
			}
		}
	
	}
}
